package org.web.base.domain;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.web.base.domain.exception.ResultMessageEnum;
import org.web.base.domain.exception.ServiceException;
import org.web.base.domain.helper.ServiceExceptionHelper;
import org.web.base.domain.view.ViewResultDTO;
import org.web.base.helper.BeanConvertHelper;

import java.util.Collection;
import java.util.List;

public class
ViewResultHelper {

    private static final Logger logger = LogManager.getLogger(ViewResultHelper.class);

    public static ViewResultDTO buildViewResultByServiceException(Exception e, String message) {
        if (e instanceof ServiceException) {
            return buildViewResultByServiceException((ServiceException) e, message);
        }
        return buildViewResultByServiceException(ServiceExceptionHelper.buildServiceException(ResultMessageEnum.SYSTEM_ERROR), message);
    }

    public static ViewResultDTO buildViewResultByServiceException(ServiceException e) {
        return buildViewResultByServiceException(e, null);
    }

    public static ViewResultDTO buildViewResultByServiceException(ServiceException e, String msg) {
        return buildViewResultByServiceException(e, msg, StringUtils.isEmpty(msg) ? msg : e.getMessage());
    }

    public static ViewResultDTO buildViewResultByServiceException(ServiceException e, String msg, String title) {
        ViewResultDTO view = new ViewResultDTO();
        view.setType(ViewResultDTO.ViewType.error.name());
        view.setResult(false);
        if (StringUtils.isNotBlank(title)) {
            view.setTitle(title);
        } else {
            view.setTitle("操作失败");
        }

        if (StringUtils.isNotBlank(msg)) {
            view.setMsg(msg);
        } else if (StringUtils.isNotBlank(e.getMessage())) {
            view.setMsg(e.getMessage());
        } else if (StringUtils.isNotBlank(e.getDescription())) {
            view.setMsg(e.getDescription());
        }

        if (e.getErrorList() != null && !e.getErrorList().isEmpty()) {
            view.setMsg(view.getMsg() + "。 " + String.join(System.lineSeparator(), e.getErrorList()));
        }

        return view;
    }

    public static <T> ViewResultDTO<T> convertToViewResultByResultDO(ResultDO resultDO, Class clazz) throws InstantiationException, IllegalAccessException {
        ViewResultDTO view = new ViewResultDTO(true);
        if (resultDO.isSuccess()) {
            view.setResult(true);
            Object sourceObject = resultDO.getDomain();
            Object targetObject = clazz.newInstance();
            if (sourceObject instanceof Collection) {
                targetObject = BeanConvertHelper.convertListToList((List<?>) sourceObject, clazz);
            } else {
                targetObject = clazz.newInstance();
                BeanUtils.copyProperties(sourceObject, targetObject);
            }
            view.setData(targetObject);
            view.setType(ViewResultDTO.ViewType.info.name());
            view.setTotalCount(Integer.parseInt(String.valueOf(resultDO.getTotalCount())));
        } else {
            logger.error(resultDO.getMessage());
            view.setResult(false);
            view.setType(ViewResultDTO.ViewType.error.name());
            view.setDetailMsg(resultDO.getMessage()); //堆栈信息过于敏感，不适合在客户端显示。
            view.setMsg(truncate(resultDO.getMessage(), 200));
        }
        return view;
    }

    /**
     * 截断字符串到指定长度
     * @param input 原始字符串
     * @param maxLength 指定的最大长度
     * @return 截断后的字符串，如果原始字符串长度小于或等于指定长度，则返回原始字符串
     */
    public static String truncate(String input, int maxLength) {
        if (input == null) {
            return null;
        }
        if (input.length() <= maxLength) {
            return input;
        }
        return input.substring(0, maxLength);
    }

    public static <T> ViewResultDTO handleBindException(BindException ex) {
        ViewResultDTO<T> viewResultDTO = new ViewResultDTO(false);
        List<FieldError> fieldErrorList = ex.getFieldErrors();
        StringBuilder errorMessage = new StringBuilder();
        if (!fieldErrorList.isEmpty()) {
            for (int i = 0; i < fieldErrorList.size(); i++) {
                FieldError fieldError = fieldErrorList.get(i);
                errorMessage.append(buildErrorMessage(fieldError));
                if (i < fieldErrorList.size() - 1) {
                    errorMessage.append("\n");
                }
            }
        } else {
            errorMessage.append(ex.getMessage());
        }
        viewResultDTO.setMsg(errorMessage.toString());
        return viewResultDTO;
    }

    private static String buildErrorMessage(FieldError fieldError) {
        StringBuilder message = new StringBuilder();
        message.append("字段 '").append(fieldError.getField()).append("' ");
        if ("typeMismatch".equals(fieldError.getCode())) {
            message.append("的类型不匹配。");
        } else {
            message.append("出错：").append(fieldError.getDefaultMessage());
        }
        message.append(" (提供的值: '").append(fieldError.getRejectedValue()).append("')");
        return message.toString();
    }
}
